"""
证书相关的业务逻辑服务
"""

from datetime import timedelta
from typing import List, Optional, Tuple, Dict
from uuid import UUID

from sqlmodel import Session, select, func, and_
from cryptography import x509
from cryptography.hazmat.primitives import hashes, serialization
from cryptography.hazmat.primitives.asymmetric import rsa
from cryptography.x509.oid import NameOID

from .certificate_model import Certificate, CertificateStatus, CertificateType
from .time_utils import beijing_now


class CertificateService:
    """证书管理服务"""

    def __init__(self, db: Session):
        self.db = db

    def create_certificate(self, certificate_data: Dict) -> Certificate:
        """
        创建新证书

        Args:
            certificate_data: 证书数据字典

        Returns:
            Certificate: 创建的证书对象
        """
        # 生成序列号
        serial_number = self._generate_serial_number()

        certificate = Certificate(serial_number=serial_number, **certificate_data)

        self.db.add(certificate)
        self.db.commit()
        self.db.refresh(certificate)

        return certificate

    def get_certificate_by_id(self, certificate_id: UUID) -> Optional[Certificate]:
        """
        根据ID获取证书

        Args:
            certificate_id: 证书ID

        Returns:
            Optional[Certificate]: 证书对象或None
        """
        return self.db.get(Certificate, certificate_id)

    def get_certificate_by_serial(self, serial_number: str) -> Optional[Certificate]:
        """
        根据序列号获取证书

        Args:
            serial_number: 证书序列号

        Returns:
            Optional[Certificate]: 证书对象或None
        """
        statement = select(Certificate).where(
            Certificate.serial_number == serial_number
        )
        return self.db.exec(statement).first()

    def list_certificates(
        self,
        page: int = 1,
        page_size: int = 20,
        certificate_type: Optional[CertificateType] = None,
        status: Optional[CertificateStatus] = None,
        aic: Optional[str] = None,
    ) -> Tuple[List[Certificate], int]:
        """
        获取证书列表

        Args:
            page: 页码
            page_size: 每页数量
            certificate_type: 证书类型过滤
            status: 状态过滤
            aic: AIC过滤

        Returns:
            Tuple[List[Certificate], int]: 证书列表和总数
        """
        statement = select(Certificate)

        # 添加过滤条件
        conditions = []
        if certificate_type:
            conditions.append(Certificate.certificate_type == certificate_type)
        if status:
            conditions.append(Certificate.status == status)
        if aic:
            conditions.append(Certificate.aic == aic)

        if conditions:
            statement = statement.where(and_(*conditions))

        # 计算总数
        count_statement = (
            select(func.count(Certificate.id)).where(and_(*conditions))
            if conditions
            else select(func.count(Certificate.id))
        )
        total = self.db.exec(count_statement).one()

        # 分页查询
        statement = statement.offset((page - 1) * page_size).limit(page_size)
        certificates = self.db.exec(statement).all()

        return certificates, total

    def update_certificate_status(
        self,
        certificate_id: UUID,
        status: CertificateStatus,
        revocation_reason: Optional[str] = None,
    ) -> Optional[Certificate]:
        """
        更新证书状态

        Args:
            certificate_id: 证书ID
            status: 新状态
            revocation_reason: 吊销原因（如果是吊销操作）

        Returns:
            Optional[Certificate]: 更新后的证书对象或None
        """
        certificate = self.get_certificate_by_id(certificate_id)
        if not certificate:
            return None

        certificate.status = status
        certificate.updated_at = beijing_now()

        if status == CertificateStatus.REVOKED:
            certificate.revoked_at = beijing_now()
            certificate.revocation_reason = revocation_reason

        self.db.commit()
        self.db.refresh(certificate)

        return certificate

    def revoke_certificate(
        self, certificate_id: UUID, reason: str
    ) -> Optional[Certificate]:
        """
        吊销证书

        Args:
            certificate_id: 证书ID
            reason: 吊销原因

        Returns:
            Optional[Certificate]: 吊销后的证书对象或None
        """
        return self.update_certificate_status(
            certificate_id, CertificateStatus.REVOKED, reason
        )

    def get_expiring_certificates(self, days_ahead: int = 30) -> List[Certificate]:
        """
        获取即将过期的证书

        Args:
            days_ahead: 提前多少天

        Returns:
            List[Certificate]: 即将过期的证书列表
        """
        expiry_threshold = beijing_now() + timedelta(days=days_ahead)
        statement = select(Certificate).where(
            and_(
                Certificate.status == CertificateStatus.VALID,
                Certificate.expires_at <= expiry_threshold,
            )
        )
        return self.db.exec(statement).all()

    def get_root_certificates(self) -> List[Certificate]:
        """
        获取所有根证书

        Returns:
            List[Certificate]: 根证书列表
        """
        statement = select(Certificate).where(
            Certificate.certificate_type == CertificateType.ROOT
        )
        return self.db.exec(statement).all()

    def get_intermediate_certificates(
        self, parent_id: Optional[UUID] = None
    ) -> List[Certificate]:
        """
        获取中间证书

        Args:
            parent_id: 父证书ID，如果指定则只返回该父证书的子证书

        Returns:
            List[Certificate]: 中间证书列表
        """
        statement = select(Certificate).where(
            Certificate.certificate_type == CertificateType.INTERMEDIATE
        )

        if parent_id:
            statement = statement.where(Certificate.parent_certificate_id == parent_id)

        return self.db.exec(statement).all()

    def _generate_serial_number(self) -> str:
        """
        生成证书序列号

        Returns:
            str: 16位十六进制序列号
        """
        import secrets

        return secrets.token_hex(8).upper()

    def generate_certificate_pair(
        self,
        subject_name: str,
        certificate_type: CertificateType,
        validity_days: int = 365,
        parent_certificate: Optional[Certificate] = None,
        aic: Optional[str] = None,
    ) -> Tuple[str, str]:
        """
        生成证书和私钥对

        Args:
            subject_name: 证书主体名称
            certificate_type: 证书类型
            validity_days: 有效期天数
            parent_certificate: 父证书（用于签名）
            aic: Agent Identify Code

        Returns:
            Tuple[str, str]: (证书PEM, 私钥PEM)
        """
        # 生成私钥
        private_key = rsa.generate_private_key(
            public_exponent=65537,
            key_size=2048,
        )

        # 创建证书主体
        subject = x509.Name(
            [
                x509.NameAttribute(NameOID.COMMON_NAME, subject_name),
            ]
        )

        # 如果有父证书，使用父证书作为签发者，否则自签名
        if parent_certificate:
            issuer_name = parent_certificate.subject
            # 这里应该加载父证书的私钥进行签名，暂时使用自签名
            signing_key = private_key
        else:
            issuer_name = subject_name
            signing_key = private_key

        issuer = x509.Name(
            [
                x509.NameAttribute(NameOID.COMMON_NAME, issuer_name),
            ]
        )

        # 创建证书
        cert_builder = x509.CertificateBuilder()
        cert_builder = cert_builder.subject_name(subject)
        cert_builder = cert_builder.issuer_name(issuer)
        cert_builder = cert_builder.public_key(private_key.public_key())
        cert_builder = cert_builder.serial_number(
            int(self._generate_serial_number(), 16)
        )
        cert_builder = cert_builder.not_valid_before(beijing_now())
        cert_builder = cert_builder.not_valid_after(
            beijing_now() + timedelta(days=validity_days)
        )

        # 添加扩展
        if certificate_type == CertificateType.ROOT:
            cert_builder = cert_builder.add_extension(
                x509.BasicConstraints(ca=True, path_length=None),
                critical=True,
            )
        elif certificate_type == CertificateType.INTERMEDIATE:
            cert_builder = cert_builder.add_extension(
                x509.BasicConstraints(ca=True, path_length=0),
                critical=True,
            )

        # 签名证书
        certificate = cert_builder.sign(signing_key, hashes.SHA256())

        # 转换为PEM格式
        cert_pem = certificate.public_bytes(serialization.Encoding.PEM).decode("utf-8")
        private_key_pem = private_key.private_bytes(
            encoding=serialization.Encoding.PEM,
            format=serialization.PrivateFormat.PKCS8,
            encryption_algorithm=serialization.NoEncryption(),
        ).decode("utf-8")

        return cert_pem, private_key_pem
